package com.xh3140.xwidget.app.sliderbar;

import android.content.Context;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.Size;

@SuppressWarnings("unused")
public abstract class AbstractSliderBar extends View {
  // 固有内边距，px
  @Size(4)
  protected final int[] mInnatePadding = {10, 10, 10, 10};
  // 滑条区域
  protected final RectF mSliderStripRectF = new RectF(0f, 0f, 0f, 0f);
  // 画笔
  protected final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  // 范围下限
  protected float mRangeLower = 0f;
  // 范围上限
  protected float mRangeUpper = 100f;
  // 滑条厚度，px
  @Px
  protected int mSliderStripThickness = 5;
  // 滑条圆角半径，px
  @Px
  protected int mSliderStripRadius = 0;
  // 滑条颜色，argb
  @ColorInt
  protected int mSliderStripColor = 0xFFDCDCDC;
  // 滑块颜色，argb
  @ColorInt
  protected int mSliderBlockColor = 0xFFFF4500;
  // 滑块半径，px
  @Px
  protected int mSliderBlockRadius = 15;
  // 滑条宽度，px
  protected int mSliderStripWidth = 0;

  // 滑块纵坐标
  protected int mSliderBlockCenter = 0;

  public AbstractSliderBar(Context context) {
    super(context);
  }

  public AbstractSliderBar(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
  }

  public AbstractSliderBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  public AbstractSliderBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  protected float v2d(float value) {
    return mSliderStripWidth * value / (mRangeUpper - mRangeLower);
  }

  protected float d2v(float distance) {
    return (mRangeUpper - mRangeLower) * distance / mSliderStripWidth;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    int measuredWidth = widthSize;
    int measuredHeight = heightSize;
    if (widthMode == MeasureSpec.AT_MOST) {
      // 滑条宽度默认120dp
      final int sliderStripWidth = (int) (120 * getResources().getDisplayMetrics().density + 0.5f);
      measuredWidth = getPaddingStart() + getPaddingEnd() + sliderStripWidth + mInnatePadding[0] + mInnatePadding[2];
    }
    if (heightMode == MeasureSpec.AT_MOST) {
      measuredHeight = getPaddingTop() + getPaddingBottom() + 2 * mSliderBlockRadius + mInnatePadding[1] + mInnatePadding[3];
    }
    setMeasuredDimension(measuredWidth, measuredHeight);
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    // 滑条区域
    mSliderStripRectF.left = getPaddingStart() + mSliderBlockRadius + mInnatePadding[0];
    mSliderStripRectF.right = getWidth() - getPaddingEnd() - mSliderBlockRadius - mInnatePadding[2];
    mSliderStripRectF.top = getPaddingTop() + (mSliderBlockRadius - mSliderStripThickness / 2f) + mInnatePadding[1];
    mSliderStripRectF.bottom = getHeight() - getPaddingBottom() - (mSliderBlockRadius - mSliderStripThickness / 2f) - mInnatePadding[3];
    mSliderStripRectF.top = Math.max(mSliderStripRectF.top, getHeight() / 2f - mSliderStripThickness / 2f);
    mSliderStripRectF.bottom = Math.min(mSliderStripRectF.bottom, getHeight() / 2f + mSliderStripThickness / 2f);
    // 滑条宽度
    mSliderStripWidth = (int) (mSliderStripRectF.right - mSliderStripRectF.left);
    // 滑块纵坐标
    mSliderBlockCenter = (int) ((mSliderStripRectF.top + mSliderStripRectF.bottom) / 2);
  }

  /**
   * 判断值在范围内
   *
   * @param value 被判断的值
   */
  public boolean isInRange(float value) {
    return value >= mRangeLower && value <= mRangeUpper;
  }

  /**
   * 约束值在范围内
   *
   * @param value 被约束的值
   */
  public float constraintInRange(float value) {
    return Math.max(mRangeLower, Math.min(value, mRangeUpper));
  }

  /**
   * 获取范围下限
   */
  public float getRangeLower() {
    return mRangeLower;
  }

  /**
   * 设置范围上限
   * 注意：这个值在不超过范围上限时才有效
   *
   * @param lower 下限
   */
  public void setRangeLower(float lower) {
    if (mRangeLower != lower && mRangeLower <= mRangeUpper) {
      mRangeLower = lower;
      invalidate();
    }
  }

  /**
   * 获取范围上限
   */
  public float getRangeUpper() {
    return mRangeUpper;
  }

  /**
   * 设置范围上限
   * 注意：这个值在不低于范围下限时才有效
   *
   * @param upper 上限
   */
  public void setRangeUpper(float upper) {
    if (mRangeUpper != upper && mRangeUpper >= mRangeLower) {
      mRangeUpper = upper;
      invalidate();
    }
  }

  /**
   * 设置范围上限
   *
   * @param lower 下限
   * @param upper 上限
   */
  public void setRange(float lower, float upper) {
    if (lower <= upper) {
      mRangeLower = lower;
      mRangeUpper = upper;
      invalidate();
    }
  }

  /**
   * 设置滑条厚度，px
   */
  public void setSliderStripThickness(@Px int thickness) {
    if (mSliderStripThickness != thickness) {
      mSliderStripThickness = thickness;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 滑条圆角半径，px
   */
  public void setSliderStripRadius(@Px int radius) {
    if (mSliderStripRadius != radius) {
      mSliderStripRadius = radius;
      requestLayout();
      invalidate();
    }
  }

  /**
   * 设置滑条颜色，argb
   */
  public void setSliderStripColor(@ColorInt int color) {
    if (mSliderStripColor != color) {
      mSliderStripColor = color;
      invalidate();
    }
  }

  /**
   * 设置滑块颜色 argb
   */
  public void setSliderBlockColor(@ColorInt int color) {
    if (mSliderBlockColor != color) {
      mSliderBlockColor = color;
      invalidate();
    }
  }

  /**
   * 设置滑块半径 px
   */
  public void setSliderBlockRadius(@Px int radius) {
    if (mSliderBlockRadius != radius) {
      mSliderBlockRadius = radius;
      requestLayout();
      invalidate();
    }
  }
}
